/*
 * Copyright (C) 2010 M. Hautle.
 * 
 * This file is part of SimpleEL.
 * 
 * SimpleEL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * SimpleEL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with SimpleEL. If not, see <http://www.gnu.org/licenses/>.
 */
package ch.simpleel.util;

import java.lang.management.*;
import ch.simpleel.data.*;

/**
 * Common parts of the speed test.
 * 
 * @author M. Hautle
 */
public abstract class Common {
    /** The number of calls to execute. */
    private static final int CALLS = 1000000;

    /** The number of runs for {@link #runTest(TheDom, TheDom, int)}. */
    private static final int ROUNDS = 10;

    /**
     * Executes the benchmark
     */
    public void executeBenchmark() throws Exception {
        final TheDom dom = createTheDom();
        final TheDom dom2 = new TheDom();
        final AOtherDom dom3 = new AOtherDom();
        runTest(dom, dom2, dom3, ROUNDS, CALLS);
        System.err.println("Real test: " + getClass().getSimpleName());
        runTest(dom, dom2, dom3, ROUNDS, CALLS);
        System.err.println("Memory:");
        MemoryMXBean mem = ManagementFactory.getMemoryMXBean();
        System.out.println("Heap: " + mem.getHeapMemoryUsage().getUsed());
        System.out.println("Non Heap: " + mem.getNonHeapMemoryUsage().getUsed());
    }

    private void runTest(TheDom dom, TheDom dom2, AOtherDom dom3, int rounds, int cnt) throws Exception {
        long[] res = new long[rounds];
        for (int i = 0; i < rounds; i++)
            res[i] = runTest(dom, dom2, dom3, cnt);
        System.out.println("Average: " + getAvg(res));
    }

    private long runTest(TheDom dom, TheDom dom2, AOtherDom dom3, int cnt) throws Exception {
        long t = System.currentTimeMillis();
        for (int i = 0; i < cnt; i++) {
            clear(dom2);
            executeCopy(dom, dom2);
            if (!check(dom2))
                throw new RuntimeException("Copy failed");
            clear(dom3);
            executeCopy(dom, dom3);
            if (!check(dom3))
                throw new RuntimeException("Copy failed");
        }
        return System.currentTimeMillis() - t;
    }

    /**
     * Copies the values of the first bean into the second one in a specific manner (depending on the benchmark)
     * 
     * @param dom The first bean to check
     * @param dom2 The second bean to check
     */
    protected abstract void executeCopy(TheDom dom, TheDom dom2) throws Exception;

    /**
     * Copies the values of the first bean into the second one in a specific manner (depending on the benchmark)
     * 
     * @param dom The first bean to check
     * @param dom2 The second bean to check
     */
    protected abstract void executeCopy(TheDom dom, AOtherDom dom2) throws Exception;

    /**
     * Create and fill an test bean.
     * 
     * @return The dom
     */
    private static TheDom createTheDom() {
        final TheDom d = new TheDom();
        d.setCity("Bern");
        d.setCountry("Switzerland");
        d.setFirstname("Bob");
        d.setName("Baumeister");
        d.setState("-");
        d.setStreet("Eigerplatz");
        d.setStreetNumber("8");
        d.setZip("3000");
        return d;
    }

    /**
     * Resets all attributes.
     * 
     * @param d The bean
     */
    private void clear(TheDom d) {
        d.setCity("");
        d.setCountry("");
        d.setFirstname("");
        d.setName("");
        d.setState("");
        d.setStreet("");
        d.setStreetNumber("");
        d.setZip("");
    }

    /**
     * Resets all attributes.
     * 
     * @param d The bean
     */
    private void clear(AOtherDom d) {
        d.setCity("");
        d.setCountry("");
        d.setFirstname("");
        d.setName("");
        d.setState("");
        d.setStreet("");
        d.setStreetNumber("");
        d.setZip("");
    }

    /**
     * Checks the test bean.
     * 
     * @param d The bean
     */
    private static boolean check(TheDom d) {
        boolean b = d.getCity().equals("Bern");
        b &= d.getCountry().equals("Switzerland");
        b &= d.getFirstname().equals("Bob");
        b &= d.getName().equals("Baumeister");
        b &= d.getState().equals("-");
        b &= d.getStreet().equals("Eigerplatz");
        b &= d.getStreetNumber().equals("8");
        b &= d.getZip().equals("3000");
        return b;
    }

    /**
     * Checks the test bean.
     * 
     * @param d The bean
     */
    private static boolean check(AOtherDom d) {
        boolean b = d.getCity().equals("Bern");
        b &= d.getCountry().equals("Switzerland");
        b &= d.getFirstname().equals("Bob");
        b &= d.getName().equals("Baumeister");
        b &= d.getState().equals("-");
        b &= d.getStreet().equals("Eigerplatz");
        b &= d.getStreetNumber().equals("8");
        b &= d.getZip().equals("3000");
        return b;
    }

    /**
     * Computes the average time out of the passed ones.
     * 
     * @param values Timing values
     * @return The average
     */
    private static double getAvg(long[] values) {
        double sum = 0;
        for (long l : values)
            sum += l;
        return sum / values.length;
    }
}
